package com.syj.nodbweb.config;
import com.google.common.base.Optional;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import io.swagger.models.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.Documentation;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.Collator;
import java.util.*;

import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList;

/**
 * @ClassName : SwaggerOrderConfig
 * @Description : 修改swagger的排序
 * @Author : 石蕴杰
 * @Date: 2020-05-12 09:03
 */
@Component
@Primary
public class SwaggerOrderConfig extends ServiceModelToSwagger2MapperImpl {
    private  static final Logger logger = LoggerFactory.getLogger(SwaggerOrderConfig.class);

    @Override
    public Swagger mapDocumentation(Documentation from) {
        Swagger swagger = super.mapDocumentation(from);
        swagger.setPaths( mapApiListings( from.getApiListings() ) );
        //排序完子目录,父目录也进行排序,按照拼音排序
         List<Tag> tags = swagger.getTags();
         Collections.sort(tags, new Comparator<Tag>() {
             @Override
             public int compare(Tag left, Tag right) {
                 String leftTag = left.getName();
                 String rightTag = right.getName();
                 Comparator<Object> com = Collator.getInstance(Locale.CHINA);
                 int position = com.compare(leftTag,rightTag);
                 return position;
             }
         });
         swagger.setTags(tags);
        return swagger;
    }

    @Override
    protected Map<String, Path> mapApiListings(Multimap<String, ApiListing> apiListings) {
        Map<String, Path> paths = new LinkedHashMap<>();
        Multimap<String, ApiListing> apiListingMap = LinkedListMultimap.create();
        Iterator iter = apiListings.entries().iterator();
        while(iter.hasNext())
        {
            Map.Entry<String, ApiListing> entry = (Map.Entry<String, ApiListing>)iter.next();
            ApiListing apis =  entry.getValue();
            List<ApiDescription> apiDesc = apis.getApis();
            List<ApiDescription> newApi = new ArrayList<>();
            for(ApiDescription a:apiDesc){
                newApi.add(a);
            }
            Collections.sort(newApi, new Comparator<ApiDescription>() {
                @Override
                public int compare(ApiDescription left, ApiDescription right) {
                    String leftPos = left.getOperations().size() == 1 ? left.getOperations().get(0).getSummary() : "";
                    String rightPos = right.getOperations().size() == 1 ? right.getOperations().get(0).getSummary() : "";
                    Comparator<Object> com = Collator.getInstance(Locale.CHINA);
                    return com.compare(leftPos,rightPos);
                }
            });
            try {
                //因ApiListing的属性都是final故需要通过反射来修改值
                ModifyFinalUtils.modify(apis, "apis", newApi);
            } catch (Exception e) {
                e.printStackTrace();
            }
            apiListingMap.put(entry.getKey(),apis);
        }

        for (ApiListing each : apiListingMap.values()) {
            for (ApiDescription api : each.getApis()) {
                paths.put(api.getPath(), mapOperations(api, Optional.fromNullable(paths.get(api.getPath()))));
            }
        }
        return paths;
    }

    private Path mapOperations(ApiDescription api, Optional<Path> existingPath) {
        Path path = existingPath.or(new Path());
        for (springfox.documentation.service.Operation each : nullToEmptyList(api.getOperations())) {
            Operation operation = mapOperation(each);
            path.set(each.getMethod().toString().toLowerCase(), operation);
        }
        return path;
    }
}

class ModifyFinalUtils {
    public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {
        Field field = object.getClass().getDeclaredField(fieldName);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        //Field 的 modifiers 是私有的
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        if(!field.isAccessible()) {
            field.setAccessible(true);
        }

        field.set(object, newFieldValue);
    }
}